unit heContnrs_SortVector_test;

{$mode objfpc}{$H+}

interface

uses
  Classes,
  fpcunit,
  heContnrs,
  heContnrs_test;

type

  TSortVectorInt = type Integer;

  { TTestSortVectorInt }

  _TTestSortVectorInt = specialize TheSortVector<TSortVectorInt>;
  TTestSortVectorInt = class(_TTestSortVectorInt)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  TSortVectorStr = type String;

  { TTestSortVectorStr }

  _TTestSortVectorStr = specialize TheSortVector<TSortVectorStr>;
  TTestSortVectorStr = class(_TTestSortVectorStr)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpSortVectorInt }

  _TTestCmpSortVectorInt = specialize TheCmpSortVector<Integer>;
  TTestCmpSortVectorInt = class(_TTestCmpSortVectorInt)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: Integer): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpSortVectorStr }

  _TTestCmpSortVectorStr = specialize TheCmpSortVector<String>;
  TTestCmpSortVectorStr = class(_TTestCmpSortVectorStr)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: String): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestCmpSortVectorInterface }

  _TTestCmpSortVectorInterface = specialize TheCmpSortVector<IInterface>;
  TTestCmpSortVectorInterface = class(_TTestCmpSortVectorInterface)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: IInterface): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TTestObjectSortVector }

  _TTestObjectSortVector = specialize TheObjectSortVector<TTracedObject>;
  TTestObjectSortVector = class(_TTestObjectSortVector)
  private
    FID: Integer;
    FTracer: TBits;
  public
    constructor Create(const ATracer: TBits; const AID: Integer);
    destructor Destroy; override;
    function Compare(const A, B: TTracedObject): Integer; override;
    property ID: Integer read FID;
    property Tracer: TBits read FTracer;
  end;

  { TheSortVectorTest }

  generic TheSortVectorTest<TVector, TItem> = class(TTestCase)
  private
    Vector: TVector;
  protected
    function Item(const N: Integer): TItem; virtual; // abstract;
    function Value(const It: TItem): Integer; virtual; // abstract;
    procedure Done(var It: TItem); virtual;
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestCreate;
    procedure TestAdd0;
    procedure TestAdd2;
    procedure TestAdd3;
    procedure TestPush;
    //procedure TestGetEnumerator;
    //procedure TestReversed;
    procedure TestClear;
    procedure TestPack;
    procedure TestGetItems;
    procedure TestSort;
    procedure TestExtract;
    procedure TestDelete;
    procedure TestIndexOf;
    procedure TestFind;
    procedure TestHas;
    procedure TestFirst;
    procedure TestLast;
    procedure TestRemove;
  end;

  { TheIntSortVectorTest }

  _TheIntSortVectorTest = specialize TheSortVectorTest<TTestSortVectorInt, Integer>;
  TheIntSortVectorTest = class(_TheIntSortVectorTest)
  protected
    function Item(const N: Integer): Integer; override;
    function Value(const It: Integer): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheStrSortVectorTest }

  _TheStrSortVectorTest = specialize TheSortVectorTest<TTestSortVectorStr, String>;
  TheStrSortVectorTest = class(_TheStrSortVectorTest)
  protected
    function Item(const N: Integer): String; override;
    function Value(const It: String): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheIntCmpSortVectorTest }

  _TheIntCmpSortVectorTest = specialize TheSortVectorTest<TTestCmpSortVectorInt, Integer>;
  TheIntCmpSortVectorTest = class(_TheIntCmpSortVectorTest)
  protected
    function Item(const N: Integer): Integer; override;
    function Value(const It: Integer): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheStrCmpSortVectorTest }

  _TheStrCmpSortVectorTest = specialize TheSortVectorTest<TTestCmpSortVectorStr, String>;
  TheStrCmpSortVectorTest = class(_TheStrCmpSortVectorTest)
  protected
    function Item(const N: Integer): String; override;
    function Value(const It: String): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheInterfaceCmpSortVectorTest }

  _TheInterfaceCmpSortVectorTest = specialize TheSortVectorTest<TTestCmpSortVectorInterface, IInterface>;
  TheInterfaceCmpSortVectorTest = class(_TheInterfaceCmpSortVectorTest)
  protected
    function Item(const N: Integer): IInterface; override;
    function Value(const It: IInterface): Integer; override;
  published
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

  { TheObjectSortVectorTest }

  _TheObjectSortVectorTest = specialize TheSortVectorTest<TTestObjectSortVector, TTracedObject>;
  TheObjectSortVectorTest = class(_TheObjectSortVectorTest)
  protected
    function Item(const N: Integer): TTracedObject; override;
    function Value(const It: TTracedObject): Integer; override;
    procedure Done(var It: TTracedObject); override;
  published
    procedure TestAdd1;
    procedure TestKill;
    procedure TestWipe;
    procedure TestGetEnumerator;
    procedure TestReversed;
  end;

implementation

uses
  SysUtils,
  testregistry;

function I2S(const N: Integer): String;
begin
  if N < 0 then
    Result := Format('N%.8x', [N])
  else
    Result := Format('P%.8x', [N]);
end;

function S2I(const S: String): Integer;
begin
  Result := StrToInt('$' + Copy(S, 2, Length(S)));
end;

{ TTestSortVectorInt }

constructor TTestSortVectorInt.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestSortVectorInt.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

{ TTestSortVectorStr }

constructor TTestSortVectorStr.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestSortVectorStr.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

{ TTestCmpSortVectorInt }

constructor TTestCmpSortVectorInt.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpSortVectorInt.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpSortVectorInt.Compare(const A, B: Integer): Integer;
begin
  Result := A - B;
end;

{ TTestCmpSortVectorStr }

constructor TTestCmpSortVectorStr.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpSortVectorStr.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpSortVectorStr.Compare(const A, B: String): Integer;
begin
  Result := SysUtils.CompareStr(A, B);
end;

{ TTestCmpSortVectorInterface }

constructor TTestCmpSortVectorInterface.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create;
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestCmpSortVectorInterface.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestCmpSortVectorInterface.Compare(const A, B: IInterface): Integer;
begin
  if (A = nil) then
    if B = nil then
      Exit(0)
    else
      Exit(1)
  else if B = nil then
    if A = nil then
      Exit(0)
    else
      Exit(-1);
  Result := (A as TInterfacedTracedObject).ID - (B as TInterfacedTracedObject).ID;
end;

{ TTestObjectSortVector }

constructor TTestObjectSortVector.Create(const ATracer: TBits; const AID: Integer);
begin
  inherited Create(True);
  FTracer := ATracer;
  FID := AID;
  if Tracer <> nil then
    Tracer[ID] := True;
end;

destructor TTestObjectSortVector.Destroy;
begin
  if Tracer <> nil then
    Tracer[ID] := False;
  inherited Destroy;
end;

function TTestObjectSortVector.Compare(const A, B: TTracedObject): Integer;
begin
  if A = B then
    Exit(0);
  if A = nil then
    Exit(-1 - B.ID);
  if B = nil then
    Exit(A.ID - (-1));
  Result := A.ID - B.ID;
end;

{ TheIntSortVectorTest }

function TheIntSortVectorTest.Item(const N: Integer): Integer;
begin
  Result := N;
end;

function TheIntSortVectorTest.Value(const It: Integer): Integer;
begin
  Result := It;
end;

procedure TheIntSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', A[J], V);
      Inc(J);
    end;
  end;
end;

procedure TheIntSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', A[J], V);
      Dec(J);
    end;
  end;
end;

{ TheStrSortVectorTest }

function TheStrSortVectorTest.Item(const N: Integer): String;
begin
  Result := I2S(N);
end;

function TheStrSortVectorTest.Value(const It: String): Integer;
begin
  Result := S2I(It);
end;

procedure TheStrSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', A[J], V);
      Inc(J);
    end;
  end;
end;

procedure TheStrSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', A[J], V);
      Dec(J);
    end;
  end;
end;

{ TheIntCmpSortVectorTest }

function TheIntCmpSortVectorTest.Item(const N: Integer): Integer;
begin
  Result := N;
end;

function TheIntCmpSortVectorTest.Value(const It: Integer): Integer;
begin
  Result := It;
end;

procedure TheIntCmpSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', A[J], V);
      Inc(J);
    end;
  end;
end;

procedure TheIntCmpSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', A[J], V);
      Dec(J);
    end;
  end;
end;

{ TheStrCmpSortVectorTest }

function TheStrCmpSortVectorTest.Item(const N: Integer): String;
begin
  Result := I2S(N);
end;

function TheStrCmpSortVectorTest.Value(const It: String): Integer;
begin
  Result := S2I(It);
end;

procedure TheStrCmpSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', A[J], V);
      Inc(J);
    end;
  end;
end;

procedure TheStrCmpSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', A[J], V);
      Dec(J);
    end;
  end;
end;

{ TheInterfaceCmpSortVectorTest }

function TheInterfaceCmpSortVectorTest.Item(const N: Integer): IInterface;
begin
  Result := TInterfacedTracedObject.Create(nil, N);
end;

function TheInterfaceCmpSortVectorTest.Value(const It: IInterface): Integer;
begin
  Result := (It as TInterfacedTracedObject).ID;
end;

procedure TheInterfaceCmpSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', Value(A[J]), Value(V));
      Inc(J);
    end;
  end;
end;

procedure TheInterfaceCmpSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', Value(A[J]), Value(V));
      Dec(J);
    end;
  end;
end;

{ TheObjectSortVectorTest }

function TheObjectSortVectorTest.Item(const N: Integer): TTracedObject;
begin
  if N = -1 then
    Exit(nil);
  Result := TTracedObject.Create(nil, N);
end;

function TheObjectSortVectorTest.Value(const It: TTracedObject): Integer;
begin
  if It = nil then
    Exit(-1);
  Result := It.ID;
end;

procedure TheObjectSortVectorTest.Done(var It: TTracedObject);
begin
  FreeAndNil(It);
end;

procedure TheObjectSortVectorTest.TestAdd1;
var
  V: TTestObjectSortVector;
  Tracer: TBits;
begin
  Tracer := TBits.Create;
  try
    V := TTestObjectSortVector.Create(nil, 0);
    try
      AssertEquals('.Add', 0, V.Add(TTracedObject.Create(Tracer, 0)));
      AssertEquals('.Count', 1, V.Count);
    finally
      V.Free;
    end;
    AssertFalse('Owned obj not freed, Tracer[0]', Tracer[0]);
  finally
    Tracer.Free;
  end;
end;

procedure TheObjectSortVectorTest.TestKill;
var
  V: TTestObjectSortVector;
  Tracer: TBits;
  Obj: TTracedObject;
begin
  Tracer := TBits.Create;
  try
    V := TTestObjectSortVector.Create(Tracer, 0);
    try
      Obj := TTracedObject.Create(Tracer, 1);
      try
        AssertTrue('V alive', Tracer[0]);
        AssertTrue('a) Obj alive', Tracer[1]);
        V.Kill;
        V := nil;
        AssertFalse('V dead', Tracer[0]);
        AssertTrue('b) Obj alive', Tracer[1]);
      finally
        Obj.Free;
      end;
    finally
      V.Free;
    end;
  finally
    Tracer.Free;
  end;
end;

procedure TheObjectSortVectorTest.TestWipe;
var
  V: TTestObjectSortVector;
  Tracer: TBits;
  Obj: TTracedObject;
begin
  Tracer := TBits.Create;
  try
    V := TTestObjectSortVector.Create(nil, 0);
    try
      Obj := TTracedObject.Create(Tracer, 1);
      try
        AssertTrue('a) Obj alive', Tracer[1]);
        V.Wipe;
        AssertEquals('.Count', 0, V.Count);
        AssertTrue('b) Obj alive', Tracer[1]);
      finally
        Obj.Free;
      end;
    finally
      V.Free;
    end;
  finally
    Tracer.Free;
  end;
end;

procedure TheObjectSortVectorTest.TestGetEnumerator;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := 0;
    for V in Vector do begin
      AssertEquals('V', Value(A[J]), Value(V));
      Inc(J);
    end;
  end;
end;

procedure TheObjectSortVectorTest.TestReversed;
const N = 10;
var
  I, J: Integer;
  V: TItem;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    J := I;
    for V in Vector.Reversed do begin
      AssertEquals('V', Value(A[J]), Value(V));
      Dec(J);
    end;
  end;
end;

{ TheSortVectorTest }

function TheSortVectorTest.Item(const N: Integer): TItem;
begin
  Assert(N = N); // hint off
  Initialize(Result); // hint off
  raise EAbstractError.Create(Format('%s.Item', [ClassName]));
end;

function TheSortVectorTest.Value(const It: TItem): Integer;
begin
  Assert(@It = @It); // hint off
  Initialize(Result); // hint off
  raise EAbstractError.Create(Format('%s.Value', [ClassName]));
end;

procedure TheSortVectorTest.Done(var It: TItem);
begin
  Assert(@It = @It); // hint off
end;

procedure TheSortVectorTest.SetUp;
begin
  Vector := TVector.Create(nil, 0);
end;

procedure TheSortVectorTest.TearDown;
begin
  FreeAndNil(Vector);
end;

procedure TheSortVectorTest.TestCreate;
begin
  AssertEquals('Initial .Count', 0, Vector.Count);
end;

procedure TheSortVectorTest.TestAdd0;
begin
  AssertEquals('.Add', 0, Vector.Add(Item(0)));
  AssertEquals('.Count', 1, Vector.Count);
end;

procedure TheSortVectorTest.TestAdd2;
const N = 10;
var I, J: Integer;
begin
  try
    for I := 1 to N do begin
      Vector.Capacity := 0;
      AssertTrue('.Capacity >= 0', Vector.Capacity >= 0);
      AssertEquals('.Add', I - 1, Vector.Add(Item(I)));
      AssertEquals('.Count', I, Vector.Count);
      AssertTrue('.Capacity > 0', Vector.Capacity > 0);
        for J := 1 to Vector.Count - 1 do
          AssertTrue('Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
    end;
  finally
    TearDown;
  end;

  SetUp;
  for I := 1 to N do begin
    Vector.Capacity := 0;
    AssertTrue('b) .Capacity >= 0', Vector.Capacity >= 0);
    AssertEquals('b) .Add', 0, Vector.Add(Item(-I)));
    AssertEquals('b) .Count', I, Vector.Count);
    AssertTrue('b) .Capacity > 0', Vector.Capacity > 0);
      for J := 1 to Vector.Count - 1 do
        AssertTrue('b) Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
  end;
end;

procedure TheSortVectorTest.TestAdd3;
const N = 10;
var
  I, J: Integer;
  A: array[0..N - 1] of TItem;
begin
  try
    for I := 0 to N - 1 do begin
      Vector.Capacity := 0;
      AssertTrue('a) .Capacity >= 0', Vector.Capacity >= 0);
      A[I] := Item(I);
      AssertEquals('a) .Add', I, Vector.Add(A[I]));
      AssertEquals('a2) .Add', Value(A[I]), Value(Vector[I]));
      AssertEquals('a) .Count', I + 1, Vector.Count);
      AssertTrue('a) .Capacity > 0', Vector.Capacity > 0);
      for J := 1 to Vector.Count - 1 do
        AssertTrue('a) Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
    end;
  finally
    TearDown;
  end;

  Setup;
  for I := 0 to N - 1 do begin
    Vector.Capacity := 0;
    AssertTrue('b) .Capacity >= 0', Vector.Capacity >= 0);
    A[I] := Item(-I);
    AssertEquals('b) .Add', 0, Vector.Add(A[I]));
    AssertEquals('b2) .Add', Value(A[I]), Value(Vector[0]));
    AssertEquals('b) .Count', I + 1, Vector.Count);
    AssertTrue('b) .Capacity > 0', Vector.Capacity > 0);
    for J := 1 to Vector.Count - 1 do
      AssertTrue('b) Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
  end;
end;

procedure TheSortVectorTest.TestPush;
const N = 10;
var
  I, J: Integer;
  A: array[0..N - 1] of TItem;
begin
  try
    for I := 0 to N - 1 do begin
      Vector.Capacity := 0;
      AssertTrue('a) .Capacity >= 0', Vector.Capacity >= 0);
      A[I] := Item(I);
      AssertEquals('a) .Push', Value(A[I]), Value(Vector.Push(A[I])));
      AssertEquals('a2) .Push', Value(A[I]), Value(Vector[I]));
      AssertEquals('a) .Count', I + 1, Vector.Count);
      AssertTrue('a) .Capacity > 0', Vector.Capacity > 0);
      for J := 1 to Vector.Count - 1 do
        AssertTrue('a) Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
    end;
  finally
    TearDown;
  end;

  Setup;
  for I := 0 to N - 1 do begin
    Vector.Capacity := 0;
    AssertTrue('b) .Capacity >= 0', Vector.Capacity >= 0);
    A[I] := Item(-I);
    AssertEquals('b) .Push', Value(A[I]), Value(Vector.Push(A[I])));
    AssertEquals('b2) .Push', Value(A[I]), Value(Vector[0]));
    AssertEquals('b) .Count', I + 1, Vector.Count);
    AssertTrue('b) .Capacity > 0', Vector.Capacity > 0);
    for J := 1 to Vector.Count - 1 do
      AssertTrue('b) Ordering', Value(Vector[J - 1]) < Value(Vector[J]));
  end;
end;

procedure TheSortVectorTest.TestClear;
const N = 10;
var I: Integer;
begin
  for I := 0 to N - 1 do
    Vector.Add(Item(I));
  Vector.Clear;
  AssertEquals('.Count', 0, Vector.Count);
end;

procedure TheSortVectorTest.TestPack;
const N = 11;
var I: Integer;
begin
  for I := 0 to N - 1 do
    Vector.Add(Item(I));
  Vector.Capacity := 2 * N;
  AssertEquals('a) .Capacity', 2 * N, Vector.Capacity);
  Vector.Pack;
  AssertEquals('b) .Capacity', Vector.Count, Vector.Capacity);
end;

procedure TheSortVectorTest.TestGetItems;
const N = 10;
var
  I, J: Integer;
  A: array[0..N - 1] of TItem;
begin
  for I := 0 to N - 1 do begin
    A[I] := Item(I);
    Vector.Add(A[I]);
    for J := 0 to I do
      AssertEquals('V', Value(A[J]), Value(Vector[J]));
  end;
end;

procedure TheSortVectorTest.TestSort;
var
  A: array[0..4] of TItem;
  I: Integer;
begin
  for I := Low(A) to High(A) do begin
    A[I] := Item(I xor $A);
    Vector.Add(A[I]);
  end;
  // 0 A
  // 1 B
  // 2 8
  // 3 9
  // 4 E
  AssertEquals('V[0]', Value(A[2]), Value(Vector[0]));
  AssertEquals('V[1]', Value(A[3]), Value(Vector[1]));
  AssertEquals('V[2]', Value(A[0]), Value(Vector[2]));
  AssertEquals('V[3]', Value(A[1]), Value(Vector[3]));
  AssertEquals('V[4]', Value(A[4]), Value(Vector[4]));
end;

procedure TheSortVectorTest.TestExtract;
var It, It2: TItem;
begin
  try
    Vector.Add(Item(0));
    It := Vector.Extract(0);
    AssertEquals('.Count', 0, Vector.Count);
    AssertEquals('It', 0, Value(It));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    Vector.Add(Item(0));
    Vector.Add(Item(1));
    It := Vector.Extract(0);
    AssertEquals('b) .Count', 1, Vector.Count);
    AssertEquals('b) It', 0, Value(It));
    It2 := Vector[0];
    AssertEquals('b2) It', 1, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    Vector.Add(Item(0));
    Vector.Add(Item(1));
    It := Vector.Extract(1);
    AssertEquals('c) .Count', 1, Vector.Count);
    AssertEquals('c) It', 1, Value(It));
    It2 := Vector[0];
    AssertEquals('c2) It', 0, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    Vector.Add(Item(0));
    Vector.Add(Item(1));
    Vector.Add(Item(2));
    It := Vector.Extract(1);
    AssertEquals('d) .Count', 2, Vector.Count);
    AssertEquals('d) It', 1, Value(It));
    It2 := Vector[0];
    AssertEquals('d2) It', 0, Value(It2));
    It2 := Vector[1];
    AssertEquals('d3) It', 2, Value(It2));
  finally
    Done(It);
    TearDown;
  end;
end;

procedure TheSortVectorTest.TestDelete;
var It, It2: TItem;
begin
  It := Item(0);
  try
    Vector.Add(It);
    Vector.Delete(0);
    AssertEquals('.Count', 0, Vector.Count);
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  Try
    It := Item(0);
    Vector.Add(It);
    Vector.Add(Item(1));
    Vector.Delete(0);
    AssertEquals('b) .Count', 1, Vector.Count);
    It2 := Vector[0];
    AssertEquals('b2) It', 1, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    It := Item(1);
    Vector.Add(Item(0));
    Vector.Add(It);
    Vector.Delete(1);
    AssertEquals('c) .Count', 1, Vector.Count);
    It2 := Vector[0];
    AssertEquals('c2) It', 0, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    It := Item(1);
    Vector.Add(Item(0));
    Vector.Add(It);
    Vector.Add(Item(2));
    Vector.Delete(1);
    AssertEquals('d) .Count', 2, Vector.Count);
    It2 := Vector[0];
    AssertEquals('d2) It', 0, Value(It2));
    It2 := Vector[1];
    AssertEquals('d3) It', 2, Value(It2));
  finally
    Done(It);
    TearDown;
  end;
end;

procedure TheSortVectorTest.TestIndexOf;
var Item0, Item1: TItem;
begin
  AssertTrue('.IndexOf', Vector.IndexOf(Item(-1)) < 0);
  Item0 := Item(100);
  Vector.Add(Item0);
  AssertTrue('b) .IndexOf', Vector.IndexOf(Item(-1)) < 0);
  AssertEquals('c) .IndexOf', 0, Vector.IndexOf(Item0));
  Item1 := Item(101);
  Vector.Add(Item1);
  AssertTrue('d) .IndexOf', Vector.IndexOf(Item(-1)) < 0);
  AssertEquals('e) .IndexOf', 0, Vector.IndexOf(Item0));
  AssertEquals('f) .IndexOf', 1, Vector.IndexOf(Item1));
  Assert(@Item0 = @Item0); // hint off
  Assert(@Item1 = @Item1); // hint off
end;

procedure TheSortVectorTest.TestFind;
var
  Item0, Item1: TItem;
  Index: Integer = 0; // hint off
begin
  AssertFalse('.Find', Vector.Find(Item(-1), Index));
  Item0 := Item(100);
  Vector.Add(Item0);
  AssertFalse('b) .Find', Vector.Find(Item(-1), Index));
  AssertTrue('c) .Find', Vector.Find(Item0, Index));
  AssertEquals('d) .Find', 0, Index);
  Item1 := Item(101);
  Vector.Add(Item1);
  AssertFalse('e) .Find', Vector.Find(Item(-1), Index));
  AssertTrue('f) .Find', Vector.Find(Item0, Index));
  AssertEquals('g) .Find', 0, Index);
  AssertTrue('h) .Find', Vector.Find(Item1, Index));
  AssertEquals('i) .Find', 1, Index);
  Assert(@Item0 = @Item0); // hint off
  Assert(@Item1 = @Item1); // hint off
end;

procedure TheSortVectorTest.TestHas;
var Item0, Item1: TItem;
begin
  AssertFalse('.Has', Vector.Has(Item(-1)));
  Item0 := Item(100);
  Vector.Add(Item0);
  AssertFalse('b) .Has', Vector.Has(Item(-1)));
  AssertTrue('c) .Has', Vector.Has(Item0));
  Item1 := Item(101);
  Vector.Add(Item1);
  AssertFalse('e) .Has', Vector.Has(Item(-1)));
  AssertTrue('f) .Has', Vector.Has(Item0));
  AssertTrue('h) .Has', Vector.Has(Item1));
  Assert(@Item0 = @Item0); // hint off
  Assert(@Item1 = @Item1); // hint off
end;

procedure TheSortVectorTest.TestFirst;
var ItemA, ItemB: TItem;
begin
  ItemA := Item(100);
  Vector.Add(ItemA);
  AssertEquals('a1) .First', Value(ItemA), Value(Vector.First));
  ItemB := Item(200);
  Vector.Add(ItemB);
  AssertEquals('a2) .First', Value(ItemA), Value(Vector.First));
  Assert(@ItemB = @ItemB); // hint off
end;

procedure TheSortVectorTest.TestLast;
var ItemA, ItemB: TItem;
begin
  ItemA := Item(100);
  Vector.Add(ItemA);
  AssertEquals('a1) .Last', Value(ItemA), Value(Vector.Last));
  ItemB := Item(200);
  Vector.Add(ItemB);
  AssertEquals('a2) .Last', Value(ItemB), Value(Vector.Last));
end;

procedure TheSortVectorTest.TestRemove;
var
  It, It2: TItem;
  Index: Integer;
begin
  try
    AssertTrue('a1) .Remove < 0', Vector.Remove(Item(-1)) < 0);
    It := Item(0);
    Vector.Add(It);
    AssertTrue('b1) .Remove < 0', Vector.Remove(Item(-1)) < 0);
    Index := Vector.Remove(It);
    AssertEquals('c1) .Remove', 0, Index);
    AssertTrue('d1) .Remove < 0', Vector.Remove(Item(-1)) < 0);
    AssertEquals('e1) .Count', 0, Vector.Count);
  finally
    Done(It);
    TearDown;
  end;

  SetUp;
  try
    It := Item(0);
    Vector.Add(It);
    Vector.Add(Item(1));
    AssertTrue('a2) .Remove < 0', Vector.Remove(Item(-1)) < 0);
    Index := Vector.Remove(It);
    AssertEquals('b2) .Remove', 0, Index);
    AssertEquals('c2) .Count', 1, Vector.Count);
    It2 := Vector[0];
    AssertEquals('d2) It', 1, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    It := Item(1);
    Vector.Add(Item(0));
    Vector.Add(It);
    Index := Vector.Remove(It);
    AssertEquals('a3) .Remove', 1, Index);
    AssertEquals('b3) .Count', 1, Vector.Count);
    It2 := Vector[0];
    AssertEquals('c3) It', 0, Value(It2));
  finally
    Done(It);
    TearDown;
  end;

  Setup;
  try
    It := Item(1);
    Vector.Add(Item(0));
    Vector.Add(It);
    Vector.Add(Item(2));
    Index := Vector.Remove(It);
    AssertEquals('a4) .Remove', 1, Index);
    AssertEquals('b4) .Count', 2, Vector.Count);
    It2 := Vector[0];
    AssertEquals('c4) It', 0, Value(It2));
    It2 := Vector[1];
    AssertEquals('d4) It', 2, Value(It2));
  finally
    Done(It);
    TearDown;
  end;
end;

initialization
  RegisterTests([
    TheIntSortVectorTest,
    TheStrSortVectorTest,
    TheIntCmpSortVectorTest,
    TheStrCmpSortVectorTest,
    TheInterfaceCmpSortVectorTest,
    TheObjectSortVectorTest
  ]);

end.

